//--------------------Sonic CD Water Script-------------------//
//--------------------Scripted by Twanvanb1-------------------//

// Aliases
#alias Object.Value0			:	Object.FrameTimer
#alias Object.Value1			:	Object.ConstBubbleTimer
#alias Object.Value2			:	Object.RandBubbleTimer
#alias Object.Value3			:	Object.Unused

// Bubble Aliases
#alias Object.Value1			:	Object.Angle
#alias Object.Value2			:	Object.XVelocity
#alias Object.Value3			:	Object.YVelocity

// HUD alias
#alias Object[24].PropertyValue	:	HUD.CurrentTimePeriod

// States
#alias 0	:	WATER_CREATEBUBBLE_1
#alias 1	:	WATER_CREATEBUBBLE_2
#alias 2	:	WATER_CREATEBUBBLE_3
#alias 3	:	WATER_CREATE_COUNT_BUBBLE_1
#alias 4	:	WATER_CREATE_COUNT_BUBBLE_2
#alias 5	:	WATER_CREATE_COUNT_BUBBLE_3
#alias 6	:	WATER_CREATE_COUNT_BUBBLE_4
#alias 7	:	WATER_CREATE_COUNT_BUBBLE_5
#alias 8	:	WATER_CREATE_COUNT_BUBBLE_6
#alias 9	:	WATER_DROWNING
#alias 10	:	WATER_DROWNED

// Priority
#alias 1	:	PRIORITY_ACTIVE

// Ink Effects
#alias 2	:	INK_ALPHA

// Global SFX
#alias 24	:	SFX_G_FLYING
#alias 25	:	SFX_G_TIRED

// Stage SFX
#alias 0	:	SFX_S_WATERSPLASH
#alias 2	:	SFX_S_DROWNING
#alias 3	:	SFX_S_AIRALERT
#alias 4	:	SFX_S_DROWNALERT

// Time Periods
#alias 0	:	TIME_PRESENT
#alias 1	:	TIME_PAST
#alias 2	:	TIME_GOOD_FUTURE
#alias 3	:	TIME_BAD_FUTURE

// Air Bubble Property Values
#alias 2	:	BUBBLE_SMALL

// Function declarations
#function Water_CreateAirBubble
#function Water_CreateCountBubble

function Water_CreateAirBubble
	if Object.ConstBubbleTimer > 0
		Object.ConstBubbleTimer--
		if Object.RandBubbleTimer > 0
			Object.RandBubbleTimer--
		else
			CreateTempObject(TypeName[Air Bubble], BUBBLE_SMALL, Player.XPos, Player.YPos)
			Object[TempObjectPos].DrawOrder = 4

			Object[TempObjectPos].YVelocity = -0x8800
			if Player.Direction == FACING_RIGHT
				Object[TempObjectPos].XPos += 0x60000
			else
				Object[TempObjectPos].XPos -= 0x60000
				Object[TempObjectPos].Angle = 256
			end if
			Object[TempObjectPos].XVelocity = Object[TempObjectPos].XPos
			Object.RandBubbleTimer = 512
		end if
	else
		Rand(TempValue0, 3)
		if TempValue0 == 1
			Rand(Object.RandBubbleTimer, 16)
			Object.RandBubbleTimer += 8
		else
			Object.RandBubbleTimer  = 512
		end if

		Object.ConstBubbleTimer = 60
		CreateTempObject(TypeName[Air Bubble], BUBBLE_SMALL, Player.XPos, Player.YPos)
		Object[TempObjectPos].DrawOrder = 4

		Object[TempObjectPos].YVelocity = -0x8800
		if Player.Direction == FACING_RIGHT
			Object[TempObjectPos].XPos += 0x60000
		else
			Object[TempObjectPos].XPos -= 0x60000
			Object[TempObjectPos].Angle = 256
		end if
		Object[TempObjectPos].XVelocity = Object[TempObjectPos].XPos
	end if
end function


function Water_CreateCountBubble
	CreateTempObject(TypeName[Countdown Bubble], TempValue0, Player.XPos, Player.YPos)
	Object[TempObjectPos].DrawOrder = 4

	Object[TempObjectPos].YVelocity = -0x8800
	if Player.Direction == FACING_RIGHT
		Object[TempObjectPos].XPos += 0x60000
	else
		Object[TempObjectPos].XPos -= 0x60000
		Object[TempObjectPos].Angle = 256
	end if
	Object[TempObjectPos].XVelocity = Object[TempObjectPos].XPos
end function


sub ObjectMain
	if Object.propertyValue == 0
		Player.WaterStream = 0
		if Object.YPos < Stage.NewWaterLevel
			Object.YPos += 0x10000
		end if
		if Object.YPos > Stage.NewWaterLevel
			Object.YPos -= 0x10000
		end if

		TempValue0   = Oscillation
		TempValue0 <<= 2
		Sin(Stage.WaterLevel, TempValue0)
		Stage.WaterLevel <<= 9
		Stage.WaterLevel  += Object.YPos

		// If the player about to enter the water
		if Player.GravityStrength == 0x3800
			if Player.YPos > Object.YPos
				if Player.State != Player_State_Death
					Player.YVelocity >>= 2
					if Object.YPos < Stage.NewWaterLevel
						Player.YVelocity += 0x10000
					end if
					if Player.State == Player_State_Fly
						StopSFX(SFX_G_FLYING)
						StopSFX(SFX_G_TIRED)
					end if
					Player.XVelocity >>= 1

					Player.Speed 	 >>= 1
					Player.TopSpeed  >>= 1
					
					Player.Acceleration >>= 1
					Player.Deceleration >>= 1

					Player.AirAcceleration >>= 1
					Player.AirDeceleration >>= 1

					Player.GravityStrength  =  0x1000
					Player.JumpStrength		=  0x38000
	#platform: Use_Origins
					if Stage.PlayerListPos == PLAYER_KNUCKLES
						Player.JumpStrength = 0x30000
					end if
	#endplatform
					Player.JumpCap			= -0x20000

					CreateTempObject(TypeName[Water Splash], 0, Player.XPos, Stage.WaterLevel)
					Object[TempObjectPos].DrawOrder = 4
					PlayStageSfx(SFX_S_WATERSPLASH, false)
					Object.ConstBubbleTimer = 52
					Player.AirTimer = 0
				end if
			end if
		else
			if Player.AirTimer == 0
				Object.State = WATER_CREATEBUBBLE_1
			end if

			switch Object.State
			case WATER_CREATEBUBBLE_1
				CallFunction(Water_CreateAirBubble)
				Player.AirTimer++
				if Player.AirTimer == 360
					PlayStageSfx(SFX_S_AIRALERT, false)
					Object.State++
				end if
				break

			case WATER_CREATEBUBBLE_2
				CallFunction(Water_CreateAirBubble)
				Player.AirTimer++
				if Player.AirTimer == 660
					PlayStageSfx(SFX_S_AIRALERT, false)
					Object.State++
				end if
				break
				
			case WATER_CREATEBUBBLE_3
				CallFunction(Water_CreateAirBubble)
				Player.AirTimer++
				if Player.AirTimer == 960
					PlayStageSfx(SFX_S_AIRALERT, false)
					Object.State++
				end if
				break

			case WATER_CREATE_COUNT_BUBBLE_1
				CallFunction(Water_CreateAirBubble)
				Player.AirTimer++
				if Player.AirTimer == 1080
					TempValue0 = 0
					CallFunction(Water_CreateCountBubble)
					Object.State++
				end if
				break

			case WATER_CREATE_COUNT_BUBBLE_2
				Player.AirTimer++
				if Player.AirTimer == 1200
					TempValue0 = 1
					CallFunction(Water_CreateCountBubble)
					Object.State++
				end if
				break

			case WATER_CREATE_COUNT_BUBBLE_3
				CallFunction(Water_CreateAirBubble)
				Player.AirTimer++
				if Player.AirTimer == 1320
					TempValue0 = 2
					CallFunction(Water_CreateCountBubble)
					Object.State++
				end if
				break

			case WATER_CREATE_COUNT_BUBBLE_4
				CallFunction(Water_CreateAirBubble)
				TempValue0  = Player.AirTimer
				TempValue0 &= 63
				if TempValue0 == 0
					PlayStageSfx(SFX_S_DROWNALERT, false)
				end if

				Player.AirTimer++
				if Player.AirTimer == 1440
					TempValue0 = 3
					CallFunction(Water_CreateCountBubble)
					Object.State++
				end if
				break

			case WATER_CREATE_COUNT_BUBBLE_5
				CallFunction(Water_CreateAirBubble)
				TempValue0  = Player.AirTimer
				TempValue0 &= 63
				if TempValue0 == 0
					PlayStageSfx(SFX_S_DROWNALERT, false)
				end if

				Player.AirTimer++
				if Player.AirTimer == 1560
					TempValue0 = 4
					CallFunction(Water_CreateCountBubble)
					Object.State++
				end if
				break

			case WATER_CREATE_COUNT_BUBBLE_6
				CallFunction(Water_CreateAirBubble)
				TempValue0  = Player.AirTimer
				TempValue0 &= 63
				if TempValue0 == 0
					PlayStageSfx(SFX_S_DROWNALERT, false)
				end if

				Player.AirTimer++
				if Player.AirTimer == 1680
					TempValue0 = 5
					CallFunction(Water_CreateCountBubble)
					Object.State++
				end if
				break

			case WATER_DROWNING
				CallFunction(Water_CreateAirBubble)
				Player.AirTimer++
				if Player.AirTimer == 1800
					if Player.State != Player_State_Death
						Stage.TimeEnabled = false
						Screen.CameraEnabled = false
						Player.State = Player_State_Drown
						Player.Animation = ANI_DROWNING

						Player.Speed	 = 0
						Player.XVelocity = 0
						Player.YVelocity = 0

						Player.TileCollisions = false
						Player.ObjectInteraction = false
						Player.DrawOrder = 5
						Object.ConstBubbleTimer = 2
						Object.Unused = 60	// ?
						PlayStageSfx(SFX_S_DROWNING, false)

						Object.State++
					end if
				end if
				break

			case WATER_DROWNED
				Player.AirTimer++
				if Player.AirTimer == 1860
					Object.State++
				end if
				if Object.ConstBubbleTimer > 0
					Object.ConstBubbleTimer--
					if Object.RandBubbleTimer > 0
						Object.RandBubbleTimer--
					else
						Rand(TempValue1, 2)
						TempValue1 += 2
						CreateTempObject(TypeName[Air Bubble], TempValue1, Player.XPos, Player.YPos)
						Object[TempObjectPos].DrawOrder = 5
						Object[TempObjectPos].YVelocity = -0x8800
						Object[TempObjectPos].YPos -= 0x60000
						Rand(Object[TempObjectPos].Angle, 256)
						Object[TempObjectPos].XVelocity = Object[TempObjectPos].XPos
						Object.RandBubbleTimer = 512
					end if
				else
					Rand(TempValue0, 4)
					if TempValue0 == 1
						Object.RandBubbleTimer = 2
					else
						Object.RandBubbleTimer = 512
					end if
					Object.ConstBubbleTimer = 6
					Rand(TempValue1, 2)
					TempValue1 += 2
					CreateTempObject(TypeName[Air Bubble], TempValue1, Player.XPos, Player.YPos)
					Object[TempObjectPos].DrawOrder = 5
					Object[TempObjectPos].YVelocity = -0x8800
					Object[TempObjectPos].YPos -= 0x60000
					Rand(Object[TempObjectPos].Angle, 256)
					Object[TempObjectPos].XVelocity = Object[TempObjectPos].XPos
				end if
				break

			end switch

			// Restore physics when exiting water
			if Player.YPos < Object.YPos
				if Player.State != Player_State_Death
					Player.YVelocity <<= 1
					if Player.YVelocity < -0x100000
						Player.YVelocity = -0x100000
					end if

					if Player.State == Player_State_Fly
						if Player.Timer < 480
							PlaySfx(SFX_G_FLYING, true)
						else
							PlaySfx(SFX_G_TIRED, true)
						end if
					end if

					Player.TopSpeed = 0x60000

					Player.Acceleration = 0xC00
					Player.Deceleration = 0xC00
					
					Player.AirAcceleration = 0x1800
					Player.AirDeceleration = 0x600

					Player.GravityStrength	= 0x3800
					// Bug Details:
					// The line below doesn't check for Knuckles.
					// So if Knuckles jumps into water and exits it, he will get Sonic's jump height.
					Player.JumpStrength		= 0x68000
					Player.JumpCap			= -0x40000

					CreateTempObject(TypeName[Water Splash], 0, Player.XPos, Stage.WaterLevel)
					Object[TempObjectPos].DrawOrder = 4
					PlayStageSfx(SFX_S_WATERSPLASH, false)
					Player.AirTimer = 0
				end if
			end if
		end if
		Stage.WaterLevel >>= 16
	else
		TempValue0 = player.xpos
		TempValue0 -= object.xpos

		if TempValue0 < 0
			FlipSign(TempValue0)
		else
			TempValue0 = TempValue0
		end if

		GetBit(TempValue2, Object.PropertyValue, 2)
		
		if TempValue2 == true
			if Player.Ypos < Object.Ypos
				if TempValue0 < 0x20 0000
					Stage.NewWaterLevel = Object.YPos
				end if
			end if
		else
			if TempValue0 < 0x20 0000
				Stage.NewWaterLevel = Object.YPos
			end if
		end if

		GetBit(TempValue2, Object.PropertyValue, 3)

		if TempValue2 == true
			if Player.Ypos > Object.Ypos
				if TempValue0 < 0x20 0000
					Stage.NewWaterLevel = Object.YPos
				end if
			end if
		else
			if TempValue0 < 0x20 0000
				Stage.NewWaterLevel = Object.YPos
			end if
		end if
	end if
end sub


sub ObjectDraw
	if Object.propertyValue == 0
		Object.FrameTimer++
		if Object.FrameTimer > 23
			Object.FrameTimer = 0
			Object.Frame++
			Object.Frame &= 3
		end if

		TempValue0   = Screen.XOffset
		Sin(TempValue1, Oscillation)
		TempValue1 >>= 5

		TempValue0 += TempValue1
		TempValue0 &= 63
		FlipSign(TempValue0)

		TempValue1  = Stage.WaterLevel
		TempValue1 -= Screen.YOffset

		TempValue2 = 0 // Make sure that the surface covers the screens xsize
		while TempValue2 <= 10 // 10 is being used as a over shot so we have some headroom.
			DrawSpriteScreenFX(Object.Frame, FX_INK, TempValue0, TempValue1)
			TempValue0 += 64
			TempValue2++
		loop
	end if
end sub


sub ObjectStartup
	LoadSpriteSheet("R4.5/Water.gif")

	Player.AirTimer = 0
	TempValue7 = -1
	
	switch Stage.ActNo
	case 1
		switch HUD.CurrentTimePeriod
		case TIME_PRESENT
			break
		case TIME_GOOD_FUTURE
		case TIME_BAD_FUTURE
			break
			
		end switch
		break

	case 2
		switch HUD.CurrentTimePeriod
		case TIME_PRESENT
			break

		case TIME_GOOD_FUTURE
		case TIME_BAD_FUTURE
			break

		end switch

		break
	end switch

	ArrayPos0 = 32
	while ArrayPos0 < 1056
		if Object[ArrayPos0].Type == TypeName[Water]
			if Object[ArrayPos0].propertyValue == 0
				Object[ArrayPos0].Priority  = PRIORITY_ACTIVE
				Object[ArrayPos0].DrawOrder = 5
				Object[ArrayPos0].InkEffect = INK_ALPHA
				Object[ArrayPos0].Alpha		= 160

				Stage.NewWaterLevel = Object[ArrayPos0].YPos

				if Player.YPos > Stage.NewWaterLevel
					Player.YVelocity >>= 2
					Player.XVelocity >>= 1

					Player.Speed 	>>= 1
					Player.TopSpeed >>= 1

					Player.Acceleration >>= 1
					Player.Deceleration >>= 1

					Player.AirAcceleration >>= 1
					Player.AirDeceleration >>= 1

					Player.GravityStrength  = 0x1000
					
					// Bug Details:
					// The line below doesn't check for Knuckles, prolly should though
					// So if Knuckles starts a scene underwater (whether it be with a checkpoint, time travelling, or anything), he'll have Sonic's jump height
					Player.JumpStrength		= 0x38000

					Object.ConstBubbleTimer = 52
				else
					Object[ArrayPos0].Priority  = PRIORITY_ACTIVE
					TempValue0 = player.xpos
					TempValue0 -= object[ArrayPos0].xpos

					if TempValue0 < 0
						FlipSign(TempValue0)
					else
						TempValue0 = TempValue0
					end if

					GetBit(TempValue2, Object[ArrayPos0].PropertyValue, 2)
		
					if TempValue2 == true
						if Player.Ypos < Object[ArrayPos0].Ypos
							if TempValue0 < 0x20 0000
								Stage.NewWaterLevel = Object[ArrayPos0].iYPos
							end if
						end if
					else
						if TempValue0 < 0x20 0000
							Stage.NewWaterLevel = Object[ArrayPos0].iYPos
						end if
					end if

					GetBit(TempValue2, Object[ArrayPos0].PropertyValue, 3)

					if TempValue2 == true
						if Player.Ypos > Object[ArrayPos0].iYpos
							if TempValue0 < 0x20 0000
								Stage.NewWaterLevel = Object[ArrayPos0].iYPos
							end if
						end if
					else
						if TempValue0 < 0x20 0000
							Stage.NewWaterLevel = Object[ArrayPos0].iYPos
						end if
					end if
				end if
			end if
		end if
		ArrayPos0++
	loop

	SpriteFrame(0, -8, 64, 16, 1, 1)	// #0 - Water Waves frame 0
	SpriteFrame(0, -8, 64, 16, 130, 1)	// #1 - Water Waves frame 1
	SpriteFrame(0, -8, 64, 16, 1, 18)	// #2 - Water Waves frame 2
	SpriteFrame(0, -8, 64, 16, 130, 18)	// #3 - Water Waves frame 3
end sub


// ========================
// Editor Subs
// ========================

sub RSDKEdit
	if editor.returnVariable == true
		switch editor.variableID
		case EDIT_VAR_PROPVAL // property value
			checkResult = object.propertyValue
			break
			
		case 0 // type
			checkResult = object.propertyValue
			break
		case 1 // Above Y
			GetBit(checkResult, object.propertyValue, 2)
			break

		case 2 // Below Y
			GetBit(checkResult, object.propertyValue, 3)
			break
			
		end switch
	else
		switch editor.variableID
		case EDIT_VAR_PROPVAL // property value
			object.propertyValue = editor.variableValue
			break
			
		case 0 // type
			object.propertyValue = editor.variableValue
			break

		case 1 // Above Y
			CheckNotEqual(editor.variableValue, false)
			SetBit(object.propertyValue, 2, checkResult)
			break
		case 2 // Below Y
			CheckNotEqual(editor.variableValue, false)
			SetBit(object.propertyValue, 3, checkResult)
			break
			
		end switch
	end if
end sub

sub RSDKDraw
	if object.propertyValue == 0
		TempValue0   = Object.XPos
		DrawSpriteXY(0, TempValue0, Object.YPos)
		TempValue0 += 0x400000
		DrawSpriteXY(0, TempValue0, Object.YPos)
		TempValue0 += 0x400000
		DrawSpriteXY(0, TempValue0, Object.YPos)
		TempValue0 += 0x400000
	else
		DrawSpriteXY(4, Object.XPos, Object.YPos)
	end if
end sub


sub RSDKLoad
	LoadSpriteSheet("R4.5/Water.gif")
	SpriteFrame(0, -8, 64, 16, 1, 1)	// #0 - Water Waves frame 0
	SpriteFrame(0, -8, 64, 16, 1, 18)	// #1 - Water Waves frame 1
	SpriteFrame(0, -8, 64, 16, 1, 35)	// #2 - Water Waves frame 2
	SpriteFrame(0, -8, 64, 16, 1, 52)	// #3 - Water Waves frame 3

	SpriteFrame(-16, -8, 32, 16, 223, 86)  // "W" (Bounds Adjust)

	AddEditorVariable("type")
	SetActiveVariable("type")
	AddEnumVariable("Regular Water", 0)
	AddEnumVariable("Water Adjust", 1)

	AddEditorVariable("Above Y")
	SetActiveVariable("Above Y")
	AddEnumVariable("false", 0)
	AddEnumVariable("true", 1)

	AddEditorVariable("Below Y")
	SetActiveVariable("Below Y")
	AddEnumVariable("false", 0)
	AddEnumVariable("true", 1)
end sub
